package com.espirit.eap.manager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

import com.espirit.eap.pagelayout.ElementService;
import com.espirit.eap.pagelayout.LayoutService;
import com.espirit.eap.pagelayout.Model;
import com.espirit.eap.sa.Privilege;
import com.espirit.eap.sa.ScopeType;
import com.espirit.eap.sa.UserTemplate;
import com.espirit.eap.sa.UserTemplatePrivilege;
import com.espirit.eap.sa.Website;
import com.googlecode.cswish.annotation.Dependence;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.ContextHolder;
import com.googlecode.cswish.struts.hibernate.DynamicModelManager;
import com.googlecode.cswish.struts.hibernate.HibernateConfiguration;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.ClassUtil;


/**
 * Manage DataBase
 * 	 
 * @author jerry.feng Date: 2008-10-24
 */
public abstract class DBAManager {
	
	@Resource
	private HibernateConfiguration hibernateConfiguration;

	@Resource
	ObjectFactory factory; 

	@Resource
	LayoutService layoutService;
	
	@Resource
	GenericService genericService;
	
	@Resource
	ElementService elementService;

	@Resource
	ObjectFactory objectFactory;
	
	@Resource
	private DynamicModelManager dynamicModelManager;
	
	@Resource
	private BeanIntrospector beanIntrospector;
	
//	@Resource
//	CSwishCoreData cswishCoreData;
	
//	@Resource
//	BaseTypeModelManager baseTypeModelManager;

	private static final Log logger = LogFactory.getLog(DBAManager.class);
	
//	protected boolean init() {
//		initDB("create-drop");
//		initModel();
//		initModelInitData();
//		initI18nData();
//		initSystemData();
//		return true;
//	}
	
//	private I18nData i18nData;
//	public void set(I18nData i18nData){
//		this.i18nData = i18nData;
//	}
//	
	public abstract void initSaasData();
	public abstract Website getDefaultWebsite();
	
	protected void builderModel(String packageName) {
		logger.debug("init package :" + packageName);
		List<ModelBuilder> builders = getBuilders(packageName);
		Set<String> done = new HashSet<String>();
		int beginSize = 0;			// for the debug facility
		int totalSize = builders.size();
		DBAManager self = objectFactory.getBean(this.getClass(), false);
		for(ModelBuilder builder : builders){
			self.buildModel(builder, done, beginSize, totalSize);
		}
		
		for(ModelBuilder builder : builders){
			self.builderMiscData(builder);
		}
	}
	
	@Transactional
	protected void buildModel(ModelBuilder builder, Set<String> done, int beginSize, int totalSize) {
		if (done.contains(builder.getClass().getName())) {
			return;
		}
		
		List<Dependence> dependences = null;
		Class clazz = builder.getClass();
		while (clazz != null) {
			Dependence dependence = (Dependence) clazz.getAnnotation(Dependence.class);
			if (dependence != null) {
				if (dependences == null) {
					dependences = new ArrayList<Dependence>();
				}
				dependences.add(dependence);
			}
			clazz = clazz.getSuperclass();
		}
		
		if (dependences != null) {
			for (Dependence dependence : dependences) {
				for (String builderName : dependence.value()) {
					if (!done.contains(builderName)) {
						ModelBuilder builderDependence = (ModelBuilder) objectFactory.getBean(builderName, true);
						buildModel(builderDependence, done, beginSize, totalSize);
					}
				}
			}
		}
		
		if (logger.isDebugEnabled()) {
			logger.debug(done.size() + "/" + totalSize + ", build :"+ builder.getClass().getName());
		}
		
		if (done.size() >= beginSize) {
			builderModelFieldsProperty(builder);
	
			builderModleFieldsInfo(builder);
	
			builderModelFields(builder);
	
			builderLayout(builder);
	
			builder.preBuildMiscData();
			
			builder.clean();
		}
		
		done.add(builder.getClass().getName());
	}
	
	protected void upradeModel(String builderName) {
		ModelBuilder builder = (ModelBuilder) factory.getBean(builderName, false);
		DBAManager self = objectFactory.getBean(this.getClass(), false);
		
		Set<String> done = new HashSet<String>();
		self.buildModel(builder, done, 0, 1);
		
		self.builderMiscData(builder);
	}
	
	private void builderModelFieldsProperty(ModelBuilder builder) {
		ModelDirector director = new ModelDirector(builder);
		director.contruct();
		builder.getResult();
	}
	private void builderModelFields(ModelBuilder builder) {
		ModelDirector director = new ModelDirector(builder);
		director.buildFields();
//		director.contruct();
//		builder.getResult();
	}
	private void builderModleFieldsInfo(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildFieldsInfo();
	}
	
	private void builderLayout(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildLayout();
	}
	
	@Transactional
	protected void builderMiscData(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildMiscData();
		
		builder.clean();
	}
	
	protected void builderModelInitData(ModelBuilder builder){
		ModelDirector director = new ModelDirector(builder);
		director.buildModelInitData();
	}
	
	protected void builderModelInitData(String packageName){
		List<ModelBuilder> builders = getBuilders(packageName);
		for(ModelBuilder builder : builders){
			builderModelInitData(builder);
		}
	}
	
	protected void initDB(String initModel){
		hibernateConfiguration.getConfigurations().get(0).setProperty("cswish.hbm2ddl.auto", initModel);
		dynamicModelManager.refreshDbSchema();
	}
	
	/*
	 * 清除页面元素数据
	 */
//	public void cleanElementData(){
//	}
	
	protected int executeSql(String hql){
		return elementService.getSession().createSQLQuery(hql).executeUpdate();
	}

//	public void initModel(){
//		cleanElementData();
//	}
	
	protected void saveI18nData(I18nData data){
		int itemCount = 0;
		for(I18n resource : data.getData()){
			I18n model = new I18n();
			model.setKey(resource.getKey());
			model = genericService.searchAll(model).getData(0);
			if (model == null ){
				genericService.add(resource);
			}
			if (++itemCount % 100 == 0){
			}
		}
		data.getData().clear();
	}
	protected abstract void initModelInitData();
	protected abstract void initI18nData();
	protected abstract  void initSystemData();
	
	
	protected List<ModelBuilder> getBuilders(String packageName){
//		if (builders == null) {
		    List<ModelBuilder> builders = new ArrayList<ModelBuilder>();
			try {
				ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 
						ClassUtils.convertClassNameToResourcePath(packageName) + "/**/*Builder.class";
				org.springframework.core.io.Resource[] resources = resolver.getResources(pattern);  
				for (org.springframework.core.io.Resource resource : resources) {
					try{
						String filename = resource.getFilename();
						String beanName = packageName + "." + filename.substring(0, filename.length() - 6);		// skip .class
						Object obj = factory.getBean(beanName, false);
						if (obj instanceof ModelBuilder){
							ModelBuilder builder = (ModelBuilder)obj;
							builders.add(builder);
							
						}
					} catch (Exception ex){
						logger.debug(ex);
					}
				}
				
			} catch (IOException ex) {
				logger.error("Read Builder", ex);
			}
//		} 
		return builders;
	}
	
	
	
	private Map<String ,Map<String ,List<Privilege>>> privileges = new HashMap<String ,Map<String ,List<Privilege>>>();
	
	protected void setUtCategoryPrivilege(UserTemplate ut,String category , ScopeType scopeType){
		setUtCategoryPrivilege(ut, category, scopeType, null);
	}
	
	protected void setUtCategoryPrivilege(UserTemplate ut,String category , ScopeType scopeType, List<String> notIncludedClass){
		logger.debug("init ut privilege data :" + ut.getName());
		String key = category;
		Map<String ,List<Privilege>> privileges =  getCategoryPrivileges(key, notIncludedClass);
		for(String Key : privileges.keySet()){
			List<Privilege> maps = privileges.get(Key);
			if (maps.size() == 1){
				UserTemplatePrivilege utp = new UserTemplatePrivilege();
				utp.setPrivilege(maps.get(0));
				utp.setUserTemplate(ut);
				genericService.merge(utp);
				ut.safeUserTemplatePrivileges().add(utp);
			} else {
				for(Privilege privilege : maps){
					if (privilege.getScopeType().equals(scopeType)){
						UserTemplatePrivilege utp = new UserTemplatePrivilege();
						utp.setPrivilege(privilege);
						utp.setUserTemplate(ut);
						ut.safeUserTemplatePrivileges().add(utp);
						break;
					}
				}
			}
		}
		genericService.merge(ut);
	}
	
	protected void setUtCategoryPrivilege(UserTemplate ut,String category){
		setUtCategoryPrivilege(ut, category,ScopeType.Global);
	}
	
	protected Map<String,List<Privilege>> getCategoryPrivileges(String categoryKey, List<String> notIncludedClass){
		if (privileges.containsKey(categoryKey)){
			return privileges.get(categoryKey);
		} else {
			
			String prefix = categoryKey;
			QLInfo qlInfo = new QLInfo("from " + Model.class.getName() 
					+ " a where a.name like '" + prefix + ".%'", false);
			List<Model> models = (List<Model>) genericService.searchByQl(qlInfo, true).getData();
			Map<String ,List<Privilege>> groupPrivileges = new HashMap<String , List<Privilege>>();
			for(Model dm : models){
				String fullModelName = beanIntrospector.getModelName(dm.getName());
				Class clazz = ClassUtil.forName(fullModelName);
				if (clazz != null && clazz.getAnnotation(
						com.espirit.eap.annotation.DomainModel.class) == null) {
					continue;
				}
				
				if (notIncludedClass != null && notIncludedClass.contains(clazz.getName())){
					continue;
				}
				
				Privilege model = new Privilege();
				model.setModelSimpleName(dm.getName());
				model = genericService.searchAll(model).getData(0);

				List<UserTemplatePrivilege> results =  new ArrayList<UserTemplatePrivilege>();
				String hql = "select a from Privilege a where a.modelSimpleName='" + dm.getName() + "' order by a.method ";
				List<Privilege> privieleges = genericService.searchByQl(new QLInfo(hql, true), false).getData();
				
				for(Privilege privilege : privieleges){
					String method = privilege.getMethod();
					if (categoryKey.equals("espirit.customerAgent") ){
						if (method.equals("getLayout")){
							continue;
						}
					}
					String key = dm.getName() + "#" + method;
					if (groupPrivileges.containsKey(key)){
						List<Privilege> mapPrivileges = groupPrivileges.get(key);
						mapPrivileges.add(privilege);
					} else {
						List<Privilege> mapPrivileges = new ArrayList<Privilege>();
						mapPrivileges.add(privilege);
						
						groupPrivileges.put(key, mapPrivileges);
					}
				}
			}
			return groupPrivileges;
		}
	}
	
	protected List getPackageModels(String packageName){
		List<Model> models = (List<Model>) genericService.searchByQl(new QLInfo("from " 
				+ Model.class.getName() + " a where a.name like ? order by a.name", true, packageName + ".%"), true).getData();
		List<Model> results = new ArrayList<Model>();
		for(Model model : models){
			String modelName = model.getName();
			String fullModelName = beanIntrospector.getModelName(modelName);
			Class clazz = ClassUtil.forName(fullModelName);
			if (clazz != null && clazz.getAnnotation(
					com.espirit.eap.annotation.DomainModel.class) == null) {
				continue;
			}
			results.add(model);
		}
		return results;
	}
	public  void createSaasSite() {
		String siteName = Website.DEFAULT_SID.toString();
		String productName = Website.DEFAULT_NAME;
		Integer compId = Website.DEFAULT_SID;
		
		ContextHolder.get().setSiteName(siteName);
		
		Website example = new Website();
		example.setCompId(compId);
		example = genericService.searchAll(example).getData(0);
		if (example != null) return ;
		
		Website model = new Website();
		model.setCompId(compId);
		model.setCompanyName("深圳搜牛科技有限公司");
		model.setProductName(productName);
		model.setCreatedOn(new Date());
		model.setLoginPage("/$/espirit/eap/sa/user._login.html");
		model.setStatus(Website.STATUS_ACTIVE);
		model.setUserCount(50);
		genericService.add(model);
	}
	
	protected void addWebSite(Integer sid, String productName){
		String siteName = sid.toString();
		ContextHolder.get().setSiteName(siteName);
		
		Website example = new Website();
		example.setCompId(sid);
		example = genericService.searchAll(example).getData(0);
		if (example != null) return ;
		
		Website model = new Website();
		model.setCompId(sid);
		model.setProductName(productName);
		model.setCreatedOn(new Date());
		model.setHomePage("");
		model.setLoginPage("/$/espirit/eap/sa/user._login.html");
		model.setStatus(1);
		model.setUserCount(50);
		genericService.add(model);
		
		
	}
}
